/*
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
 * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * File: $Id: mbfuncholding_m.c,v 1.60 2013/09/02 14:13:40 Armink Add Master Functions  Exp $
 */

/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"

/* ----------------------- Platform includes --------------------------------*/
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbconfig.h"
#include "mbframe.h"
#include "mbproto.h"

/* ----------------------- Defines ------------------------------------------*/
#define MB_PDU_REQ_READ_ADDR_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_REQ_READ_REGCNT_OFF (MB_PDU_DATA_OFF + 2)
#define MB_PDU_REQ_READ_SIZE (4)
#define MB_PDU_FUNC_READ_REGCNT_MAX (0x007D)
#define MB_PDU_FUNC_READ_BYTECNT_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_READ_VALUES_OFF (MB_PDU_DATA_OFF + 1)
#define MB_PDU_FUNC_READ_SIZE_MIN (1)

#define MB_PDU_REQ_WRITE_ADDR_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_REQ_WRITE_VALUE_OFF (MB_PDU_DATA_OFF + 2)
#define MB_PDU_REQ_WRITE_SIZE (4)
#define MB_PDU_FUNC_WRITE_ADDR_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_WRITE_VALUE_OFF (MB_PDU_DATA_OFF + 2)
#define MB_PDU_FUNC_WRITE_SIZE (4)

#define MB_PDU_REQ_WRITE_MUL_ADDR_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_REQ_WRITE_MUL_REGCNT_OFF (MB_PDU_DATA_OFF + 2)
#define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF (MB_PDU_DATA_OFF + 4)
#define MB_PDU_REQ_WRITE_MUL_VALUES_OFF (MB_PDU_DATA_OFF + 5)
#define MB_PDU_REQ_WRITE_MUL_SIZE_MIN (5)
#define MB_PDU_REQ_WRITE_MUL_REGCNT_MAX (0x0078)
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF (MB_PDU_DATA_OFF + 2)
#define MB_PDU_FUNC_WRITE_MUL_SIZE (4)

#define MB_PDU_REQ_READWRITE_READ_ADDR_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_REQ_READWRITE_READ_REGCNT_OFF (MB_PDU_DATA_OFF + 2)
#define MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF (MB_PDU_DATA_OFF + 4)
#define MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF (MB_PDU_DATA_OFF + 6)
#define MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF (MB_PDU_DATA_OFF + 8)
#define MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF (MB_PDU_DATA_OFF + 9)
#define MB_PDU_REQ_READWRITE_SIZE_MIN (9)
#define MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF (MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_READWRITE_READ_VALUES_OFF (MB_PDU_DATA_OFF + 1)
#define MB_PDU_FUNC_READWRITE_SIZE_MIN (1)

/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception(eMBErrorCode eErrorCode);

/* ----------------------- Start implementation -----------------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0

/**
 * This function will request write holding register.   0x06  写单个保持寄存器   周六晚上打球,主要是活动活动腰和背
 *
 * @param ucSndAddr salve address
 * @param usRegAddr register start address
 * @param usRegData register data to be written
 * @param lTimeOut timeout (-1 will waiting forever)
 *
 * @return error code
 */
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister(UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut)
{
    UCHAR* ucMBFrame;
    eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;

    if (ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM) { // 从站地址在 1~247之间
        eErrStatus = MB_MRE_ILL_ARG;
    } else if (xMBMasterRunResTake(lTimeOut) == FALSE) // 一般是会一直等的直到等到为止
    {
        eErrStatus = MB_MRE_MASTER_BUSY;
    } else {
        vMBMasterGetPDUSndBuf(&ucMBFrame); // 这里指向功能码
        vMBMasterSetDestAddress(ucSndAddr);
        ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_REGISTER;
        ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usRegAddr >> 8;
        ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usRegAddr;
        ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8;
        ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData;
        vMBMasterSetPDUSndLength(MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE);
        (void)xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
        eErrStatus = eMBMasterWaitRequestFinish();
    }
    return eErrStatus;
}

eMBException eMBMasterFuncWriteHoldingRegister(UCHAR* pucFrame, USHORT* usLen)
{ // 这里应该是处理从站传过来的数据的  那不一定当广播时有 pucFrame指向modbus发送缓冲区   非广播时有 pucFrame指向modbus接收缓冲区
    USHORT usRegAddress;
    eMBException eStatus = MB_EX_NONE;
    eMBErrorCode eRegStatus;

    if (*usLen == (MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_SIZE)) { // 功能码 + 起始地址(2字节) + 数据(2字节)
        usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8);
        usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1]);
        usRegAddress++;

        /* Make callback to update the value. pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF]这里指向变更的数据  */
        eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF], usRegAddress, 1, MB_REG_WRITE);

        /* If an error occured convert it into a Modbus exception. */
        if (eRegStatus != MB_ENOERR) {
            eStatus = prveMBError2Exception(eRegStatus);
        }
    } else {
        /* Can't be a valid request because the length is incorrect. */
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
    }
    return eStatus; // 返回的是modbus标准错误码
}
#endif

#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0

/**
 * This function will request write multiple holding register.  0x10
 *
 * @param ucSndAddr salve address
 * @param usRegAddr register start address
 * @param usNRegs register total number
 * @param pusDataBuffer data to be written
 * @param lTimeOut timeout(-1 will waiting forever)
 *
 * @return error code
 */
eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister(UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, USHORT* pusDataBuffer, LONG lTimeOut)
{ //
    UCHAR* ucMBFrame; // 项目中用到的modbus主站像是以空间换时间(要发送的数据帧都已经准备好了)   这里的modbus应该是以时间来换空间(要发送的数据帧得当场组装起来)
    USHORT usRegIndex = 0;
    eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;

    if (ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM) {
        eErrStatus = MB_MRE_ILL_ARG;
    } else if (xMBMasterRunResTake(lTimeOut) == FALSE) { // 这里是获取信号量失败
        eErrStatus = MB_MRE_MASTER_BUSY;
    } else {
        vMBMasterGetPDUSndBuf(&ucMBFrame); // ucMBFrame 指向了功能吗  其实指向了ucMasterRTUSndBuf
        vMBMasterSetDestAddress(ucSndAddr);
        ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
        ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usRegAddr >> 8;
        ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usRegAddr;
        ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] = usNRegs >> 8;
        ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] = usNRegs;
        ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = usNRegs * 2; // 表示下面的数据的字节数
        ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF; // 指向了实际的数据位
        while (usNRegs > usRegIndex) { // 寄存器的个数
            *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8; // 高字节
            *ucMBFrame++ = pusDataBuffer[usRegIndex++]; // 低字节
        }
        // 退出时  usNRegs等于usRegIndex
        vMBMasterSetPDUSndLength(MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2 * usNRegs); // 就是除去 从站地址和CRC校验的
        (void)xMBMasterPortEventPost(EV_MASTER_FRAME_SENT); // 发送是单独的线程
        eErrStatus = eMBMasterWaitRequestFinish();
    }
    return eErrStatus;
}

eMBException eMBMasterFuncWriteMultipleHoldingRegister(UCHAR* pucFrame, USHORT* usLen) // 这个pucFrame没有使用
{ // 这里是modbus标准错误码  //pucFrame指向接收到的modbus数据的第二个字节 即功能码   usLen里面存储的是除 (Address + CRC之外的长度)
    UCHAR* ucMBFrame;
    USHORT usRegAddress;
    USHORT usRegCount;
    UCHAR ucRegByteCount;

    eMBException eStatus = MB_EX_NONE; // 这里是modbus标准错误
    eMBErrorCode eRegStatus;

    /* If this request is broadcast, the *usLen is not need check. */
    if ((*usLen == MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_MUL_SIZE) || xMBMasterRequestIsBroadcast()) { // 功能码  +  （起始地址 + 寄存器数）
        vMBMasterGetPDUSndBuf(&ucMBFrame); // 指向发送数据帧的功能码
        usRegAddress = (USHORT)(ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] << 8);
        usRegAddress |= (USHORT)(ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1]);
        usRegAddress++; //

        usRegCount = (USHORT)(ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] << 8);
        usRegCount |= (USHORT)(ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1]);

        ucRegByteCount = ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF]; // 字节数

        if (ucRegByteCount == 2 * usRegCount) { // 寄存器数量转字节数
            /* Make callback to update the register values.  ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF]传入的是数据字节 */
            eRegStatus = eMBMasterRegHoldingCB(&ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF], usRegAddress, usRegCount, MB_REG_WRITE);
            // 这个函数是 写多个保持寄存器
            /* If an error occured convert it into a Modbus exception. */
            if (eRegStatus != MB_ENOERR) {
                eStatus = prveMBError2Exception(eRegStatus);
            }
        } else {
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
        }
    } else {
        /* Can't be a valid request because the length is incorrect. */
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
    }
    return eStatus;
}
#endif

#if MB_FUNC_READ_HOLDING_ENABLED > 0

/**
 * This function will request read holding register.   //这里是发送命令用的 0x03
 *
 * @param ucSndAddr salve address
 * @param usRegAddr register start address
 * @param usNRegs register total number
 * @param lTimeOut timeout (-1 will waiting forever)
 *
 * @return error code
 */
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister(UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut)
{
    UCHAR* ucMBFrame;
    eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;

    if (ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM)
        eErrStatus = MB_MRE_ILL_ARG;
    else if (xMBMasterRunResTake(lTimeOut) == FALSE)
        eErrStatus = MB_MRE_MASTER_BUSY;
    else {
        vMBMasterGetPDUSndBuf(&ucMBFrame);
        vMBMasterSetDestAddress(ucSndAddr);
        ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_HOLDING_REGISTER;
        ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8;
        ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr;
        ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
        ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
        vMBMasterSetPDUSndLength(MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE); // 除去 从站地址 和 CRC校验
        (void)xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
        eErrStatus = eMBMasterWaitRequestFinish();
    }
    return eErrStatus;
}

eMBException eMBMasterFuncReadHoldingRegister(UCHAR* pucFrame, USHORT* usLen) // 这里是接收命令用的
{ // pucFrame指向接收到的modbus数据的第二个字节 即功能码   usLen里面存储的是除 (Address + CRC之外的长度)
    UCHAR* ucMBFrame;
    USHORT usRegAddress; // 这个数据从modbus发送帧中取得
    USHORT usRegCount; // 这个数据从modbus发送帧中取得

    eMBException eStatus = MB_EX_NONE; // 表示没有错误
    eMBErrorCode eRegStatus;

    /* If this request is broadcast, and it's read mode. This request don't need execute. */
    if (xMBMasterRequestIsBroadcast()) {
        eStatus = MB_EX_NONE; // 读操作是没有广播的
    } else if (*usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN) {

        // 功能码和数据域字节数  // 大于等于2字节
        vMBMasterGetPDUSndBuf(&ucMBFrame); // ucMBFrame指向了功能码 指向的是发送的
        usRegAddress = (USHORT)(ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8); // 要读取寄存器的起始地址的高字节
        usRegAddress |= (USHORT)(ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1]); // 要读取寄存器的起始地址的低字节
        usRegAddress++; // 这里加一,后面还得减一

        usRegCount = (USHORT)(ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8);
        usRegCount |= (USHORT)(ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1]);

        /* Check if the number of registers to read is valid. If not
         * return Modbus illegal data value exception.
         */
        if ((usRegCount >= 1) && (2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF])) { // 这里表示 要求读取的寄存器个数大于等于1 并且返回的寄存器数目==希望读取的寄存器数目
            /* Make callback to fill the buffer. */
            eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount, MB_REG_READ);
            // 其实值都写进了usMRegHoldBuf中;
            /* If an error occured convert it into a Modbus exception. pucFrame[MB_PDU_FUNC_READ_VALUES_OFF]指向读取的数据区域*/
            if (eRegStatus != MB_ENOERR) {
                eStatus = prveMBError2Exception(eRegStatus);
            }
        } else {
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
        }
    } else {
        /* Can't be a valid request because the length is incorrect. */
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
    }
    return eStatus;
}

#endif

#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0

/**
 * This function will request read and write holding register. 23=0x17  读写多个寄存器
 *
 * @param ucSndAddr salve address
 * @param usReadRegAddr read register start address
 * @param usNReadRegs read register total number
 * @param pusDataBuffer data to be written   //专门是写
 * @param usWriteRegAddr write register start address
 * @param usNWriteRegs write register total number
 * @param lTimeOut timeout (-1 will waiting forever)
 *
 * @return error code
 */
eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister(UCHAR ucSndAddr, USHORT usReadRegAddr, USHORT usNReadRegs, USHORT* pusDataBuffer, USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut)
{ // 以优异成绩,但这里有一个前提,就是身体不能跨......
    UCHAR* ucMBFrame;
    USHORT usRegIndex = 0;
    eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;

    if (ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM)
        eErrStatus = MB_MRE_ILL_ARG;
    else if (xMBMasterRunResTake(lTimeOut) == FALSE)
        eErrStatus = MB_MRE_MASTER_BUSY;
    else {
        vMBMasterGetPDUSndBuf(&ucMBFrame); // 指向功能码
        vMBMasterSetDestAddress(ucSndAddr);
        ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;

        ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] = usReadRegAddr >> 8;
        ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] = usReadRegAddr; // 读寄存器开始地址
        ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] = usNReadRegs >> 8;

        ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] = usNReadRegs; // 读寄存器总数
        ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] = usWriteRegAddr >> 8;
        ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] = usWriteRegAddr; // 写寄存器开始地址

        ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] = usNWriteRegs >> 8;
        ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] = usNWriteRegs; // 写寄存器总数
        ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF] = usNWriteRegs * 2;

        ucMBFrame += MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF; // 去除从机地址 + CRC校验
        while (usNWriteRegs > usRegIndex) {
            *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
            *ucMBFrame++ = pusDataBuffer[usRegIndex++];
        }

        vMBMasterSetPDUSndLength(MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2 * usNWriteRegs);
        (void)xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
        eErrStatus = eMBMasterWaitRequestFinish();
    }
    return eErrStatus;
}

// 这里的pucFrame指向modbus发送缓冲(广播时)  pucFrame指向modbus接收缓冲(单播时)
eMBException eMBMasterFuncReadWriteMultipleHoldingRegister(UCHAR* pucFrame, USHORT* usLen)
{ // 和牛逼的人在一起,和强者较量！！！  让自己变得更强   华科还是得考的！！！！
    USHORT usRegReadAddress;
    USHORT usRegReadCount;
    USHORT usRegWriteAddress;
    USHORT usRegWriteCount;
    UCHAR* ucMBFrame;

    eMBException eStatus = MB_EX_NONE;
    eMBErrorCode eRegStatus;

    /* If this request is broadcast, and it's read mode. This request don't need execute. */
    if (xMBMasterRequestIsBroadcast()) { // 读对应的功能码函数   不处理广播
        eStatus = MB_EX_NONE; // 功能码    +    数据域字节数
    } else if (*usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READWRITE_SIZE_MIN) {
        vMBMasterGetPDUSndBuf(&ucMBFrame); // 指向modbus发送区的功能码
        usRegReadAddress = (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] << 8U);
        usRegReadAddress |= (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1]);
        usRegReadAddress++;

        usRegReadCount = (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] << 8U);
        usRegReadCount |= (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1]);

        usRegWriteAddress = (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] << 8U);
        usRegWriteAddress |= (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1]);
        usRegWriteAddress++;

        usRegWriteCount = (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] << 8U);
        usRegWriteCount |= (USHORT)(ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1]); // 8

        // 要求读取的数据字节数等于实际返回的数据字节数
        if ((2 * usRegReadCount) == pucFrame[MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF]) {
            /* Make callback to update the register values.    ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF]指向实际的数据(发送区)   应该是写给从机的*/
            eRegStatus = eMBMasterRegHoldingCB(&ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF], usRegWriteAddress, usRegWriteCount, MB_REG_WRITE); // 这里相当于自己给自己写,假想和上面写给从机的数据保持同步

            if (eRegStatus == MB_ENOERR) {
                /* Make the read callback. pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF]指向modbus接收缓冲区的实际数据   实际从从机读取的数据   然后写到相应的内存中*/
                eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF], usRegReadAddress, usRegReadCount, MB_REG_READ);
            }
            if (eRegStatus != MB_ENOERR) {
                eStatus = prveMBError2Exception(eRegStatus);
            }
        } else {
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
        }
    }
    return eStatus;
}

#endif
#endif
